/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

//===========================================================================================
#include <dylab/simulation/InputEvent.h>
#include <dylab/utils/exceptions/EInvalidArgument.h>

//===========================================================================================
dylab::InputEvent::StrKeyCodeMap dylab::InputEvent::s_mStrKeyCodeMap;
//-----------------------------------------------------------------------------
#define KC2STR(kc) #kc
#define STORE_KC(kc, mapw) mapw.insert(KC2STR(kc), kc);
//-----------------------------------------------------------------------------
dylab::String dylab::InputEvent::keyCode2Str(const keycode_t & _keyCode)
{
    return KC2STR(_keyCode);
}
//-----------------------------------------------------------------------------
dylab::InputEvent::keycode_t dylab::InputEvent::str2KeyCode(const String & _str)
{
    if (s_mStrKeyCodeMap.getCount() == 0)
    {
        StrKeyCodeMap::Writer strkc(s_mStrKeyCodeMap);
        STORE_KC(KC_UNASSIGNED, strkc);
        STORE_KC(KC_ESCAPE, strkc);
		STORE_KC(KC_1, strkc);
		STORE_KC(KC_2, strkc);
		STORE_KC(KC_3, strkc);
		STORE_KC(KC_4, strkc);
		STORE_KC(KC_5, strkc);
		STORE_KC(KC_6, strkc);
		STORE_KC(KC_7, strkc);
		STORE_KC(KC_8, strkc);
		STORE_KC(KC_9, strkc);
		STORE_KC(KC_0, strkc);
		STORE_KC(KC_MINUS, strkc);
		STORE_KC(KC_EQUALS, strkc);
		STORE_KC(KC_BACK, strkc);
		STORE_KC(KC_TAB, strkc);
		STORE_KC(KC_Q, strkc);
		STORE_KC(KC_W, strkc);
		STORE_KC(KC_E, strkc);
		STORE_KC(KC_R, strkc);
		STORE_KC(KC_T, strkc);
		STORE_KC(KC_Y, strkc);
		STORE_KC(KC_U, strkc);
		STORE_KC(KC_I, strkc);
		STORE_KC(KC_O, strkc);
		STORE_KC(KC_P, strkc);
		STORE_KC(KC_LBRACKET, strkc);
		STORE_KC(KC_RBRACKET, strkc);
		STORE_KC(KC_RETURN, strkc);
		STORE_KC(KC_LCONTROL, strkc);
		STORE_KC(KC_A, strkc);
		STORE_KC(KC_S, strkc);
		STORE_KC(KC_D, strkc);
		STORE_KC(KC_F, strkc);
		STORE_KC(KC_G, strkc);
		STORE_KC(KC_H, strkc);
		STORE_KC(KC_J, strkc);
		STORE_KC(KC_K, strkc);
		STORE_KC(KC_L, strkc);
		STORE_KC(KC_SEMICOLON, strkc);
		STORE_KC(KC_APOSTROPHE, strkc);
		STORE_KC(KC_GRAVE, strkc);
		STORE_KC(KC_LSHIFT, strkc);
		STORE_KC(KC_BACKSLASH, strkc);
		STORE_KC(KC_Z, strkc);
		STORE_KC(KC_X, strkc);
		STORE_KC(KC_C, strkc);
		STORE_KC(KC_V, strkc);
		STORE_KC(KC_B, strkc);
		STORE_KC(KC_N, strkc);
		STORE_KC(KC_M, strkc);
		STORE_KC(KC_COMMA, strkc);
		STORE_KC(KC_PERIOD, strkc);
		STORE_KC(KC_SLASH, strkc);
		STORE_KC(KC_RSHIFT, strkc);
		STORE_KC(KC_MULTIPLY, strkc);
		STORE_KC(KC_LMENU, strkc);
		STORE_KC(KC_SPACE, strkc);
		STORE_KC(KC_CAPITAL, strkc);
		STORE_KC(KC_F1, strkc);
		STORE_KC(KC_F2, strkc);
		STORE_KC(KC_F3, strkc);
		STORE_KC(KC_F4, strkc);
		STORE_KC(KC_F5, strkc);
		STORE_KC(KC_F6, strkc);
		STORE_KC(KC_F7, strkc);
		STORE_KC(KC_F8, strkc);
		STORE_KC(KC_F9, strkc);
		STORE_KC(KC_F10, strkc);
		STORE_KC(KC_NUMLOCK, strkc);
		STORE_KC(KC_SCROLL, strkc);
		STORE_KC(KC_NUMPAD7, strkc);
		STORE_KC(KC_NUMPAD8, strkc);
		STORE_KC(KC_NUMPAD9, strkc);
		STORE_KC(KC_SUBTRACT, strkc);
		STORE_KC(KC_NUMPAD4, strkc);
		STORE_KC(KC_NUMPAD5, strkc);
		STORE_KC(KC_NUMPAD6, strkc);
		STORE_KC(KC_ADD, strkc);
		STORE_KC(KC_NUMPAD1, strkc);
		STORE_KC(KC_NUMPAD2, strkc);
		STORE_KC(KC_NUMPAD3, strkc);
		STORE_KC(KC_NUMPAD0, strkc);
		STORE_KC(KC_DECIMAL, strkc);
		STORE_KC(KC_OEM_102, strkc);
		STORE_KC(KC_F11, strkc);
		STORE_KC(KC_F12, strkc);
		STORE_KC(KC_F13, strkc);
		STORE_KC(KC_F14, strkc);
		STORE_KC(KC_F15, strkc);
		STORE_KC(KC_KANA, strkc);
		STORE_KC(KC_ABNT_C1, strkc);
		STORE_KC(KC_CONVERT, strkc);
		STORE_KC(KC_NOCONVERT, strkc);
		STORE_KC(KC_YEN, strkc);
		STORE_KC(KC_ABNT_C2, strkc);
		STORE_KC(KC_NUMPADEQUALS, strkc);
		STORE_KC(KC_PREVTRACK, strkc);
		STORE_KC(KC_AT, strkc);
		STORE_KC(KC_COLON, strkc);
		STORE_KC(KC_UNDERLINE, strkc);
		STORE_KC(KC_KANJI, strkc);
		STORE_KC(KC_STOP, strkc);
		STORE_KC(KC_AX, strkc);
		STORE_KC(KC_UNLABELED, strkc);
		STORE_KC(KC_NEXTTRACK, strkc);
		STORE_KC(KC_NUMPADENTER, strkc);
		STORE_KC(KC_RCONTROL, strkc);
		STORE_KC(KC_MUTE, strkc);
		STORE_KC(KC_CALCULATOR, strkc);
		STORE_KC(KC_PLAYPAUSE, strkc);
		STORE_KC(KC_MEDIASTOP, strkc);
		STORE_KC(KC_VOLUMEDOWN, strkc);
		STORE_KC(KC_VOLUMEUP, strkc);
		STORE_KC(KC_WEBHOME, strkc);
		STORE_KC(KC_NUMPADCOMMA, strkc);
		STORE_KC(KC_DIVIDE, strkc);
		STORE_KC(KC_SYSRQ, strkc);
		STORE_KC(KC_RMENU, strkc);
		STORE_KC(KC_PAUSE, strkc);
		STORE_KC(KC_HOME, strkc);
		STORE_KC(KC_UP, strkc);
		STORE_KC(KC_PGUP, strkc);
		STORE_KC(KC_LEFT, strkc);
		STORE_KC(KC_RIGHT, strkc);
		STORE_KC(KC_END, strkc);
		STORE_KC(KC_DOWN, strkc); 
		STORE_KC(KC_PGDOWN, strkc);
		STORE_KC(KC_INSERT, strkc);
		STORE_KC(KC_DELETE, strkc);
		STORE_KC(KC_LWIN, strkc); 
		STORE_KC(KC_RWIN, strkc); 
		STORE_KC(KC_APPS, strkc); 
		STORE_KC(KC_POWER, strkc);
		STORE_KC(KC_SLEEP, strkc);
		STORE_KC(KC_WAKE, strkc); 
		STORE_KC(KC_WEBSEARCH, strkc);
		STORE_KC(KC_WEBFAVORITES, strkc);
		STORE_KC(KC_WEBREFRESH, strkc);
		STORE_KC(KC_WEBSTOP, strkc);
		STORE_KC(KC_WEBFORWARD, strkc);
		STORE_KC(KC_WEBBACK, strkc);
		STORE_KC(KC_MYCOMPUTER, strkc);
		STORE_KC(KC_MAIL, strkc); 
		STORE_KC(KC_MEDIASELECT, strkc);
    }

    keycode_t kc;    
    if (!s_mStrKeyCodeMap.find(_str, &kc))
        throw EInvalidArgument(String::fmt("Can't convert string '%1%' to key code. The string is not valid.", _str));    

    return kc;            
}
//-----------------------------------------------------------------------------


//===========================================================================================
dylab::InputEvent::InputEvent(type_t _type, keycode_t _keyCode)
: mType(_type), mKeyCode(_keyCode)
{     
}
//-----------------------------------------------------------------------------
dylab::InputEvent::InputEvent(type_t _type, uint32_t _mouseAbsX, uint32_t _mouseAbsY, 
            real_t _mouseRelX, real_t _mouseRelY, uint32_t _mouseButtons)
: mType(_type), mMouseAbsX(_mouseAbsX), mMouseAbsY(_mouseAbsY)
, mMouseRelX(_mouseRelX), mMouseRelY(_mouseRelY), mMouseButtons(_mouseButtons)
{
}
//-----------------------------------------------------------------------------
dylab::InputEvent::~InputEvent()
{ 
}
//-----------------------------------------------------------------------------
dylab::InputEvent::type_t dylab::InputEvent::getType() const
{
    return mType;
}
//-----------------------------------------------------------------------------
dylab::InputEvent::keycode_t dylab::InputEvent::getKeyCode() const
{
    return mKeyCode;
}
//-----------------------------------------------------------------------------
dylab::uint32_t dylab::InputEvent::getMouseAbsX() const
{
    return mMouseAbsX;
}
//-----------------------------------------------------------------------------
dylab::uint32_t dylab::InputEvent::getMouseAbsY() const
{
    return mMouseAbsY;
}
//-----------------------------------------------------------------------------
dylab::real_t dylab::InputEvent::getMouseRelX() const
{
    return mMouseRelX;
}
//-----------------------------------------------------------------------------
dylab::real_t dylab::InputEvent::getMouseRelY() const
{
    return mMouseRelY;
}
//-----------------------------------------------------------------------------
bool dylab::InputEvent::isMouseButtonDown(mousebutton_t _mouseButton) const
{
// performance warning
#if defined(DYLAB_COMPILER_MSVC)
#   pragma warning (push)
#   pragma warning (disable : 4800)
#endif

	return mMouseButtons & (1 << _mouseButton);

// performance warning
#if defined(DYLAB_COMPILER_MSVC)
#   pragma warning (pop)
#endif
}    
//-----------------------------------------------------------------------------